# from datetime import datetime
import os.path
from datetime import datetime

from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.http import HttpResponse
from django.shortcuts import render, redirect

# Create your views here.
# from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views import View

from django_study.settings import MEDIA_ROOT
from .form import ArticleForms
from .models import *


def test(request, *args, **kwargs):  # django 会将用户的请求封装起来 自动传一个参数
    # print(request)
    # print(kwargs)  # **kwargs字典不定长
    # info = kwargs.get('info')
    # print(info)
    # print('Zzz')
    user = User.objects.get(username='lisa')
    # 校验密码 check_passwork参数跟数据库保存的字符是否一致
    # 如果一致的话返回True 如果不一致则返回False
    user.check_password('zw14750')
    return HttpResponse('<h1>holl</h1>')  # 并且返回一个响应对象（字符串）


def TCL(request, **kwargs):
    return HttpResponse('电视机')


# 用户以登录


# 用户未登录
# user = None

# 报文
def nav(request, **kwargs):
    # data = {  # 以字典的形式保存的数据 Python c Java deepseek
    #     'python': [{  # 以列表的形式保存多个 字典
    #         'title': 'Python常用医疗AI库以及案例解析（2025年版、上）',
    #         "desc": "PyCharm是Python专用IDE，含调试、智能提示等高效工具，这是详细安装教程。",
    #         'detail': "https://blog.csdn.net/2302_79751907/article/details/149197592",
    #         'img': 'https://i-blog.csdnimg.cn/direct/e227d66a60944bf1ab91a3ce6f78b1d9.png#pic_center',
    #     },
    #         {
    #             'title': '用 python 开发一个可调用工具的 AI Agent，实现电脑配置专业评价',
    #             "desc": '本文详细介绍如何使用 Python 编写一个可调用工具的 AI Agent，现实对电脑配置进行评价的功能。',
    #             'detail': "https://blog.csdn.net/dudly/article/details/148618978",
    #             'img': 'https://i-blog.csdnimg.cn/direct/5710e3b5e4c1435487aea07ff4692471.gif',
    #         }],
    #     'c': [{
    #         'title': '【C++】迭代器失效',
    #         "desc": "定义 迭代器失效是指在使用迭代器遍历容器（如vectorlistmap等）的过程中，由于容器内部结构发生了变化，导致原来的迭代器不再有效，不能正确地指向它原本所指向的元素或者不能按照预期的方式进行遍历。​	当在vector中插入元素时，如果插入操作导致了内存重新分配，那么所有指向该vector的迭代器都会失效。这是因为vector的存储是连续的内存空间，当插入元素使得当前容量不够时，vector会重新分配一块更大的内存空间，将原来的元素复制或移动到中，原来的迭代器所指向的内存地址就不再有效。",
    #         'detail': "https://blog.csdn.net/Stromboli/article/details/142552381?spm=1000.2115.3001.10526&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-3-142552381-null-null.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-3-142552381-null-null.nonecase",
    #         'img': 'https://i-blog.csdnimg.cn/direct/acadceab39d7469ea60afd865ace1fc7.gif#pic_center',
    #     }],
    #     'java': [{
    #         'title': '飞算 JavaAI 体验：重塑 Java 开发的智能新范式',
    #         "desc": "本文结合政务、金融、电商等领域的实际项目，详细介绍了飞算 JavaAI 在工程化代码生成、智能重构、团队协作等方面的应用，包括注册安装流程，分析了其优势、局限及应对方法，为 Java 开发者提供了实用参考。",
    #         'detail': "https://blog.csdn.net/atgfg/article/details/149275144",
    #         'img': 'https://i-blog.csdnimg.cn/direct/5d2c502c15b84a77bda2ee38cc1a7a7d.png#pic_center',
    #     },
    #         {
    #             'title': '飞算 JavaAI 使用体验全解析',
    #             "desc": "《飞算JavaAI：专为Java开发者打造的智能编程助手》 随着AI技术的普及，众多编程助手工具涌现，但大多缺乏对特定语言的深度支持。飞算JavaAI(CalEx-JavaAI)是一款专为Java开发者设计的智能开发助手，提供从需求分析到代码生成的全流程智能引导。本文介绍了其安装配置、核心功能与使用体验，包括智能开发全流程引导、Java/SQL智能问答等特色功能。通过与Copilot等通用工具的对比，突显其在Java开发中的专业优势。",
    #             'detail': "https://blog.csdn.net/qyj19920704/article/details/149035174",
    #             'img': 'https://i-blog.csdnimg.cn/direct/b32fe367706d47feb576967361e2c037.png',
    #
    #         },
    #         {
    #             'title': '飞算JavaAI测评——弑Date宣言：我在铁屋实验室用飞算JavaAI引爆代码——47分钟血洗技术债，一个学生的“起义”',
    #             "desc": "        深夜01:47，实验室上的报表泛着冷光，像极了鲁迅笔下“人血浸透的馒头”。键盘敲下的第37个“收到”，成了枷锁新焊的一环。这工位敞亮如无菌室，却比铁屋更窒闷——中央空调嘶吐着“卷”字的魂，啃噬窗边最后一缕月光…… ",
    #             'detail': "https://blog.csdn.net/Pocker_Spades_A/article/details/149033339",
    #             'img': 'https://i-blog.csdnimg.cn/direct/7d059ddf7d1d4ac09ec468f17a6588b6.png#pic_center',
    #         }],
    #     'deepseek': [
    #         # {
    #         #     'title': 'AI+游戏开发：如何用 DeepSeek 打造高性能贪吃蛇游戏',
    #         #     "desc": " Vue.js项目开发全程实录》精选Vue.js开发方向的10个热门应用项目，实用性非常强。这些项目包含：智汇企业官网首页设计、贪吃蛇小游戏、时光音乐网首页设计、游戏公园博客、电影易购APP、淘贝电子商城、畅联通讯录、仿饿了么APP、仿今日头条APP、四季旅游信息网。本书从软件工程的角度出发，按照项目开发的顺序，系统而全面地讲解每一个项目的开发实现过程。体例上，每章聚焦一个项目，统一采用“开发背景→系统设计→技术准备→各功能模块的设计与实现→项目运行→源码下载”的形式完整呈现项目。",
    #         #     'detail': "https://blog.csdn.net/qq_32682301/article/details/146171988",
    #         #     'img': 'https://i-blog.csdnimg.cn/direct/3706df84745f4a14b5d0493de66d3a9b.png',
    #         # }
    #     ]
    # }

    classes = kwargs.get('classes')
    # 地址栏传递的分类 转换器接收到的字符数据
    # print(classes)
    # 拿到文章数据

    # if not res:  # 值为false 取反为Ture
    #     # return redirect('/Z/404/')
    #     print(reverse(' not_found'))
    #     return redirect(' not_found')

    # return  HttpResponse(f'文章{classes}下的数据{res}')
    # render渲染模板工具
    # return  HttpResponse(render(request,'Z/nav.html'))
    # data.keys()获取所有的键名

    # 得到模型类里面的分类对象
    try:
        # 如果获取不到该分类 就会报错
        res = Classes.objects.get(name=classes)  # 条件 取得地址栏中的对应分类
    except Classes.DoesNotExist:
        return redirect('not_found')
    # 如果分类不存在则跳转到404页面 获取时会报错
    # if not res:
    #     return redirect(' not_found')
    username = request.user.username
    return HttpResponse(render(request,
                               'Z/nav.html',
                               context={
                                   # 'articles': res,
                                   'articles': res.article_set.all(),
                                   # 通过管理器得到分类下的所有文章数据
                                   # 当前 路由 访问的分类名 一个
                                   'now_cls': classes,
                                   # 数据里面的分类名 多个
                                   # 'classes': data.keys(),
                                   # 得到模型类里面的所有分类对象
                                   'classes': Classes.objects.all(),
                                   'user': username,
                                   # 'str1': 'hello',
                                   # 'num': 100,
                                   # 'html':'<h1> hello </h1>'
                               }))


def not_found(request, **kwargs):
    return HttpResponse('该页面不存在！')


def index(request, **kwargs):
    # Django会自动获取请求中的cookie 再到数据库中的session 来匹配
    username = request.user.username
    return HttpResponse(render(request,
                               'Z/index.html',
                               context={
                                   # 之前classes.html中的 i表示的是 字典中的对象data.keys()
                                   # 'classes': data.keys(),
                                   'classes': Classes.objects.all(),
                                   # 'user': User.objects.get(username='lisa')
                                   'user': username,
                               }))


def classes(request, **kwargs):
    # 一 、往表里加数据 实际就是在实例化一个对象 并且传入一个字段值
    # classes1 = Classes(name='python')
    # classes1.save() #保存数据

    # 二 、创建一个对象
    # classes2 = Classes()
    #     # 给模型对象属性赋值
    # classes2.name = 'java'
    # classes2.save()

    # 三 、通过类调用创建的方法创建对象传值
    # Classes.objects.create(name='c')

    # 四 、get_or_create获取或者创建
    # 有数据就获取 ，没有就添加
    # Classes.objects.get_or_create(name='deepseek')

    # 查询 所有数据 单条（条件） 多条（条件）
    # res = Classes.objects.all()  # 类（Classes）的所有（all）对象（objects）
    # for i in res:
    #     print(i.name)
    # # print(res)
    # # 查单条
    # res1 = Classes.objects.get(name='c')
    # print(res1)
    # # 查多条 条件查询
    # res2 = Classes.objects.filter(name='python')
    # print(res2)

    # 修改数据  先获取
    # 修改单条数据
    # 修改单条数据
    # rest = Classes.objects.get(name='c')
    # rest.name = 'C'
    # rest.save()

    # 修改多条 查询集不是一个对象
    # Classes.objects.filter(name='python').update(name = 'python3')

    # 删除单条 和 删除多条
    # Classes.objects.get(name='c').delete()
    # 删多条
    # Classes.objects.filter(name='c').delete()

    # 以上都是查询的操作
    return HttpResponse('数据更新成功')


def tab_info(request, **kwargs):
    #     一对一表关系
    # 创建一个用户 密码是明文保存
    # user = User(username='lisa')
    # user.set_password('zw14750')  # m密码加密方法
    # user.save()  # 保存
    # 创建一个用户详情对象
    # 如果 上面有用户对象就直接关联对象，
    # UserDetail.objects.create(age=2, sex=0, user_id=3) # 第二种方法根据ID来添加 用户对象
    # UserDetail.objects.create(age=20, sex=0, user=user)  # 1.user 表对象   2.user 关联对象  一定要有user对象

    # 一对一查询
    # 获取用户为‘Lisa’的年龄
    # 首先获取用户对象
    # user = User.objects.get(username='lisa')
    # 因为用户表关联了用户详情表，所以用户对象拥有用户详情表属性 相当于得到了以后详情对象
    # 可以直接通过，字段名获取到对应的属性值
    # print(user.userdetail.age)

    # 先获取id为1的用户详情的名字
    # 先得到用户详情对象
    # userdetail = UserDetail.objects.get(id=1)
    # print(userdetail.user.username)

    # 一对多
    # classes = Classes.objects.create(name='test')
    #
    # # 创建一个文章对象
    # artacle =Article(title='test',desc='test-desc',content='test-content',
    #         cover='https://i-blog.csdnimg.cn/direct/3706df84745f4a14b5d0493de66d3a9b.png',
    #         user_id=1, classes=classes, )
    # artacle.save()
    # classes=Classes.objects.get(name='test')
    # # 得到Python分类下 文章名字为test的文章内容  content 属性
    # print( classes.article_set.get(title='test').content)# 管理器名字

    # 一对多管理器表数据添加
    # classes = Classes.objects.get(name='python')
    # # 通过管理器来添加
    # classes.article_set.create(title='test3',desc='test3',content='test3',cover='https://i-blog.csdnimg.cn/direct/3706df84745f4a14b5d0493de66d3a9b.png',
    #                            user_id=1,classes=classes  ) # article  _set 代表多条数据查询

    # 一对多 管理器 表数据修改 /添加
    # classes = Classes.objects.get(name='python')
    # classes.article_set.add(Article.objects.get(title='test'))

    # 多对多的表数据添加
    # 给test1这篇文章添加两个标签
    # 1.先获取test1标签
    # article = Article.objects.get(title='test')
    # article.label.create(name='test111')
    # article.label.create(name='test222')

    # 表数据删除
    # 1.获取test的文章
    # article = Article.objects.get(title='test')
    # 2.获取test222的标签
    # test = article.label.create(name='test222')
    # article.label.remove(test)
    # 只移除关系表的记录  Z_article_label  而不是关联表中的内容

    # 删除全部数据  也只移除关系表的记录  单表删除
    # article.label.clear()

    #  多张表查询
    # 1.获取文章标题为test的标签
    # 首先要获取test的文章
    # article = Article.objects.get(title='test')
    # label = Label.objects.get(name='test')
    # article.label.all() #label 标签表
    # label.article_set.all()  #article 文章表

    # 多表串联查询
    # 1.获取ID为1的分类的文章中的用户详情
    # print(UserDetail.objects.filter(user__article__classes_id=1))  #user__article__classes_id=1  两个__是实现跨表查询
    # # 获取python 分类下的文章
    # print(Article.objects.filter(classes__name='python'))
    return HttpResponse('成功')


class AddArticleView(View):
    # 添加登录校验的权限 auth 系统 不会在session表中查询
    @method_decorator(login_required)
    def get(self, request):
        form = ArticleForms()
        # username = request.session.get('username')
        username = request.user.username
        return render(request, 'Z/add_article.html', {'user': username, 'form': form})

    def post(self, request):
        # 绑定用户数据表单对象
        # 当需要使用表单时并且需要绑定文件数据 文件数据需要跟普通的表单数据分开处理
        # 文件数据并不会放到POST 而是放在file中
        # print(request.POST)
        # print(request.FILES)
        form = ArticleForms(request.POST, request.FILES)
        print(request.POST)
        print(request.FILES)
        username = request.user.username  # 获取用户对象
        if form.is_valid():
            title = form.cleaned_data.get('title')
            desc = form.cleaned_data.get('desc')
            content = form.cleaned_data.get('content')
            cover = form.cleaned_data.get('cover')
            classes = form.cleaned_data.get('classes')
            # 多对多的表关系 得到多个数据
            labels = form.cleaned_data.get('label')
            user = request.user
            # 保存图片时 图片名可能会重复 要重写图片名>把时间戳跟图片名拼接
            file_name = f'{datetime.now().strftime("%Y%m%d%H%S")}_{cover.name}'
            # 图片地址
            with open(os.path.join(MEDIA_ROOT, file_name), 'wb') as fp:
                # 当图片文件过大时会卡顿 chunks 上传的文件数据分批次写入
                for data in cover.chunks():
                    fp.write(data)

            # 创建文章模型对象
            article = Article.objects.create(title=title, desc=desc, content=content, cover=file_name, user=user,
                                             classes=classes, )
            for i in labels:
                article.label.add(i)

        return render(request, 'Z/add_article.html', {'user': username, 'form': form})


class ArticleDetailView(View):
    # 查看一篇文章的详情内容 需要通过id什么知道这是哪一篇文章
    def get(self, request, id):
        try:
            article = Article.objects.get(id=id)
        except Article.DoesNotExist:
            return redirect(' not_found')
        return render(request, 'Z/article_detail.html', context={'article': article, 'labels': article.label.all()})


# 创作中心页面
class ArticleUserView(View):
    # 添加权限校验
    @method_decorator(login_required())
    def get(self, request):
        articles = Article.objects.filter(user=request.user)
        # 让Django自动帮我们分页
        pg = Paginator(articles, 3)
        try:
            pg_current = request.GET.get('page')  # 获取当前页面
            # 获取当前的页面数据
            pages = pg.page(pg_current)
        # 如果页面不是一个整数，默认显示第一页
        except PageNotAnInteger:
            pages = pg.page(1)
            # 当page参数超过有效范围就显示最后一页
        except EmptyPage:
            pages = pg.page(pg.num_pages)
        return render(request, "Z/user_article.html",
                      {'user': request.user.username, 'articles': articles, 'pages': pages})


class ArticleUpdateView(View):
    # 添加权限校验
    @method_decorator(login_required)
    # 你要修改那篇文章
    def get(self, request, id):

        try:
            article = Article.objects.get(id=id)
        except:
            return redirect(' not_found')
        else:
            # 如果能够正常获取文章数据，就定义一个字典保存修改后的文章数据
            data = {
                'title': article.title,
                'desc': article.desc,
                'content': article.content,
                'classes': article.classes,
                'label': article.label.all(),
            }
        form = ArticleForms(data)

        return render(request, 'Z/update_article.html',
                      {"user": request.user.username, "form": form})

    def post(self, request):
        form = ArticleForms(request.POST, request.FILES)
        print(request.POST)
        print(request.FILES)
        username = request.user.username  # 获取用户对象
        if form.is_valid():
            title = form.cleaned_data.get('title')
            desc = form.cleaned_data.get('desc')
            content = form.cleaned_data.get('content')
            cover = form.cleaned_data.get('cover')
            classes = form.cleaned_data.get('classes')
            # 多对多的表关系 得到多个数据
            labels = form.cleaned_data.get('label')
            user = request.user
            # 保存图片时 图片名可能会重复 要重写图片名>把时间戳跟图片名拼接
            file_name = f'{datetime.now().strftime("%Y%m%d%H%S")}_{cover.name}'
            # 图片地址
            with open(os.path.join(MEDIA_ROOT, file_name), 'wb') as fp:
                # 当图片文件过大时会卡顿 chunks 上传的文件数据分批次写入
                for data in cover.chunks():
                    fp.write(data)
                    #查询获取之前的文章信息
            articles = Article.objects.filter(id = id)
            #删除之前保存的图片
            os.remove(os.path.join(MEDIA_ROOT, articles[0].cover))
            #保存到数据库中

            # 创建文章模型对象
            articles.update(title=title, desc=desc, content=content, cover=file_name, user=user,
                                             classes=classes, )
            articles[0].label.clear()

            for i in labels:
                articles[0].label.add(i)

            return redirect('ArticleUser')


class ArticleDelete(View):
    # 查看一篇文章的详情内容 需要通过id什么知道这是哪一篇文章
    def get(self, request, id):
        try:
            article = Article.objects.get(id=id)
        except Article.DoesNotExist:
            return redirect(' not_found')
        os.remove(os.path.join(MEDIA_ROOT, article.cover))
        article.delete()
        return redirect("ArticleUser")